package top.zhangjianyong.tools.indicator.score;

import lombok.Data;

import java.math.BigDecimal;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * 技术指标综合打分结果
 * 存储各指标得分和综合得分结果
 *
 * @author zhangjianyong
 * @date 2024/01/01
 */
@Data
public class IndicatorScoreResult {

    /**
     * MACD指标得分
     */
    private BigDecimal macdScore;

    /**
     * KDJ指标得分
     */
    private BigDecimal kdjScore;

    /**
     * 布林带指标得分
     */
    private BigDecimal bollScore;

    /**
     * RSI指标得分
     */
    private BigDecimal rsiScore;

    /**
     * 均线系统得分
     */
    private BigDecimal movingAverageScore;

    /**
     * 成交量指标得分
     */
    private BigDecimal volumeScore;

    /**
     * 其他指标得分（ADX和OBV）
     */
    private BigDecimal otherScore;

    /**
     * 综合得分
     */
    private BigDecimal totalScore;

    /**
     * 信号类型：BUY(买入)、SELL(卖出)、HOLD(观望)
     */
    private SignalType signalType;

    /**
     * 信号强度：STRONG(强)、MEDIUM(中等)、WEAK(弱)
     */
    private SignalStrength signalStrength;

    /**
     * 各指标投票结果（-1卖出、0观望、1买入）
     */
    private Map<String, Integer> indicatorVotes = new LinkedHashMap<>();

    /**
     * 阈值配置
     */
    public static class Threshold {
        private BigDecimal buyThreshold = new BigDecimal("3.0");
        private BigDecimal sellThreshold = new BigDecimal("-3.0");
        private BigDecimal strongThreshold = new BigDecimal("5.0");
        private BigDecimal mediumThreshold = new BigDecimal("2.0");

        public BigDecimal getBuyThreshold() {
            return buyThreshold;
        }

        public void setBuyThreshold(BigDecimal buyThreshold) {
            this.buyThreshold = buyThreshold;
        }

        public BigDecimal getSellThreshold() {
            return sellThreshold;
        }

        public void setSellThreshold(BigDecimal sellThreshold) {
            this.sellThreshold = sellThreshold;
        }

        public BigDecimal getStrongThreshold() {
            return strongThreshold;
        }

        public void setStrongThreshold(BigDecimal strongThreshold) {
            this.strongThreshold = strongThreshold;
        }

        public BigDecimal getMediumThreshold() {
            return mediumThreshold;
        }

        public void setMediumThreshold(BigDecimal mediumThreshold) {
            this.mediumThreshold = mediumThreshold;
        }
    }

    private static final Threshold DEFAULT_THRESHOLD = new Threshold();

    /**
     * 信号类型枚举
     */
    public enum SignalType {
        /**
         * 买入信号（总分 > 3分）
         */
        BUY("买入"),

        /**
         * 卖出信号（总分 < -3分）
         */
        SELL("卖出"),

        /**
         * 观望信号（-3 ≤ 总分 ≤ 3分）
         */
        HOLD("观望");

        private final String description;

        SignalType(String description) {
            this.description = description;
        }

        public String getDescription() {
            return description;
        }
    }

    /**
     * 信号强度枚举
     */
    public enum SignalStrength {
        /**
         * 强信号（|总分| > 4）
         */
        STRONG("强"),

        /**
         * 中等信号（2 < |总分| ≤ 4）
         */
        MEDIUM("中等"),

        /**
         * 弱信号（|总分| ≤ 2）
         */
        WEAK("弱");

        private final String description;

        SignalStrength(String description) {
            this.description = description;
        }

        public String getDescription() {
            return description;
        }
    }

    /**
     * 根据综合得分判断信号类型和强度
     *
     * @param totalScore 综合得分
     */
    public void determineSignal(BigDecimal totalScore) {
        this.totalScore = totalScore;

        Threshold threshold = DEFAULT_THRESHOLD;

        // 判断信号类型
        if (totalScore.compareTo(threshold.getBuyThreshold()) > 0) {
            this.signalType = SignalType.BUY;
        } else if (totalScore.compareTo(threshold.getSellThreshold()) < 0) {
            this.signalType = SignalType.SELL;
        } else {
            this.signalType = SignalType.HOLD;
        }

        // 判断信号强度
        BigDecimal absScore = totalScore.abs();
        if (absScore.compareTo(threshold.getStrongThreshold()) > 0) {
            this.signalStrength = SignalStrength.STRONG;
        } else if (absScore.compareTo(threshold.getMediumThreshold()) > 0) {
            this.signalStrength = SignalStrength.MEDIUM;
        } else {
            this.signalStrength = SignalStrength.WEAK;
        }
    }

    public static Threshold getDefaultThreshold() {
        return DEFAULT_THRESHOLD;
    }

    public void addVote(String indicator, int vote) {
        if (indicator != null) {
            indicatorVotes.put(indicator, vote);
        }
    }
}

